package ru.urfc.portal.model.radio;

import static ru.urfc.portal.ui.client.Constants.*;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;

import ru.urfc.portal.model.SpectrObject;
import ru.urfc.portal.model.catalogs.AntennaPolarization;
import ru.urfc.portal.model.catalogs.AntennaType;
import ru.urfc.portal.model.catalogs.RayClass;
import ru.urfc.portal.ui.client.Constants;

@Table(name = "portal_sectors")
@Entity
@XmlRootElement(name = Constants.SECTOR)
public class DeviceSector extends SpectrObject {

	private DeviceWithExtra device;
	@ManyToOne(fetch = FetchType.EAGER)
	public AntennaType antennaType;
	@ManyToOne(fetch = FetchType.EAGER)
	@JoinColumn(name = "antennaPolarization_code")
	public AntennaPolarization polarization;
	public Integer height;
	public Double azimuthMinDegrees;
	public Integer azimuthMinMinutes;
	public Double azimuthMaxDegrees;
	public Integer azimuthMaxMinutes;
	@XmlElementWrapper(name = Constants.SECTOR_FREQUENCIES_LIST)
	@XmlElement(name = Constants.SECTOR_FREQUENCIES_ITEM)
	@OneToMany(mappedBy = "sector")
	public List<DeviceSectorFrequencies> frequenciesList;
	@JoinTable(name = "portal_sectorrayclasses",
			joinColumns = @JoinColumn(name = "sector_id"),
			inverseJoinColumns = @JoinColumn(name = "rayClass_id"))
	@XmlTransient
	public List<RayClass> raysClassList;

	public DeviceSector() {
		super();
	}
	
	public DeviceSector(DeviceWithExtra device, AntennaType antennaType,
			AntennaPolarization polarization, Integer height,
			Double azimuthMinDegrees, Integer azimuthMinMinutes,
			Double azimuthMaxDegrees, Integer azimuthMaxMinutes,
			List<RayClass> raysClassList) {
		super();
		this.device = device;
		this.antennaType = antennaType;
		this.polarization = polarization;
		this.height = height;
		this.azimuthMinDegrees = azimuthMinDegrees;
		this.azimuthMinMinutes = azimuthMinMinutes;
		this.azimuthMaxDegrees = azimuthMaxDegrees;
		this.azimuthMaxMinutes = azimuthMaxMinutes;
		this.raysClassList = raysClassList;
	}

	@XmlTransient
	public DeviceWithExtra getDevice() {
		return device;
	}

	static public interface VisiorAcceptor {
		String accept(Visitor visitor);
	}
	
	static public class Visitor {
		private boolean forFrequenciesIn = true;
				
		public Visitor() {
			super();
		}

		public Visitor(boolean forFrequenciesIn) {
			this.forFrequenciesIn = forFrequenciesIn;
		}
		
		public String accept(RayClass rayClass) {
			return rayClass.getName();
		}
		
		public String accept(DeviceSectorFrequencies frequencies) {
			Long frequency = forFrequenciesIn? frequencies.getFrequencyIn(): frequencies.getFrequencyOut();
			return frequency.toString();
		}
		
	}
	
	@XmlElement
	public String getRayClasses() {
		return listToString(raysClassList, new Visitor(), new Comparator<RayClass>() {
			@Override
			public int compare(RayClass o1, RayClass o2) {
				return o1.getName().compareTo(o2.getName());
			}
		});
	}

	@XmlElement
	public String getFrequenciesIn() {
		return listToString(frequenciesList, new Visitor(), new Comparator<DeviceSectorFrequencies>() {
			@Override
			public int compare(DeviceSectorFrequencies o1, DeviceSectorFrequencies o2) {
				return o1.getFrequencyIn().compareTo(o2.getFrequencyIn());
			}
		});
	}

	@XmlElement
	public String getFrequenciesOut() {
		return listToString(frequenciesList, new Visitor(false), new Comparator<DeviceSectorFrequencies>() {
			@Override
			public int compare(DeviceSectorFrequencies o1, DeviceSectorFrequencies o2) {
				return o1.getFrequencyOut().compareTo(o2.getFrequencyOut());
			}
		});
	}
	
	private <T extends VisiorAcceptor> String listToString(List<T> list, Visitor visitor, Comparator<T> comparator) {
		List<T> sortedList = new ArrayList<T>(list);
		Collections.sort(sortedList, comparator);
		StringBuilder result = new StringBuilder();
		for (VisiorAcceptor item: sortedList) {
			if (result.length()!= 0) {
				result.append(NUMBER_LIST_SEPARATOR);
			}
			result.append(item.accept(visitor));
		}
		return result.toString();
	}
	
}
